package com.speaktoitcookbook.util;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 数据库操作工具类，本类主要完成数据库常用的相关操作
 * 
 * @author 杨强
 */
public class DBUtil {

    /**
     * 查询数据库中的数据，数据以数组集合形式返回<br/>
     * 此方法不会关闭connection
     * 
     * @param conn
     *            数据库连接
     * @param sql
     *            数据库SQL语句
     * @param values
     *            可选参数，查询条件
     * @return 结果集合
     * @throws SQLException
     *             数据库异常
     */
    public static List<Object[]> query(Connection conn, String sql,
            Object... values) throws SQLException {
        List<Object[]> result = new ArrayList<Object[]>();
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = conn.prepareStatement(sql);
            if (null != values && values.length > 0) {
                int item = 1;
                for (int i = 0; i < values.length; i++) {
                    if (null != values[i] && values[i].getClass().isArray()) {
                        Object[] array = (Object[]) values[i];
                        for (int j = 0; j < array.length; j++) {
                            ps.setObject(item++, array[j]);
                        }
                    } else {
                        ps.setObject(item++, values[i]);
                    }
                }
            }
            rs = ps.executeQuery();
            while (rs.next()) {
                ResultSetMetaData rsmd = rs.getMetaData();
                Object[] objects = new Object[rsmd.getColumnCount()];
                for (int i = 0; i < objects.length; i++) {
                    Object object = rs.getObject(i + 1);
                    objects[i] = object;
                }
                result.add(objects);
            }
        } catch (SQLException e) {
            throw e;
        } finally {
            DBUtil.closeAll(ps, rs);
        }
        return result;
    }

    /**
     * 查询数据库中的数据，数据以数组集合形式返回，每条数据以Map的形式返回，其中key对应列名，value对应值<br/>
     * 此方法不会关闭connection
     * 
     * @param conn
     *            数据库连接
     * @param sql
     *            数据库SQL语句
     * @param values
     *            可选参数，查询条件
     * @return 结果集合
     * @throws SQLException
     *             数据库异常
     */
    public static List<Map<String, Object>> queryForMap(Connection conn,
            String sql, Object... values) throws SQLException {
        List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = conn.prepareStatement(sql);
            if (null != values && values.length > 0) {
                int item = 1;
                for (int i = 0; i < values.length; i++) {
                    if (null != values[i] && values[i].getClass().isArray()) {
                        Object[] array = (Object[]) values[i];
                        for (int j = 0; j < array.length; j++) {
                            ps.setObject(item++, array[j]);
                        }
                    } else {
                        ps.setObject(item++, values[i]);
                    }
                }
            }
            rs = ps.executeQuery();
            while (rs.next()) {
                ResultSetMetaData rsmd = rs.getMetaData();
                Map<String, Object> map = new HashMap<String, Object>();
                int length = rsmd.getColumnCount();
                for (int i = 0; i < length; i++) {
                    map.put(rsmd.getColumnLabel(i + 1), rs.getObject(i + 1));
                }
                result.add(map);
            }
        } catch (SQLException e) {
            throw e;
        } finally {
            DBUtil.closeAll(ps, rs);
        }
        return result;
    }
    
    /**
     * 操作（增、删、改）数据库中的一条数据<br/>
     * 此方法不会关闭connection
     * 
     * @param conn
     *            数据库连接
     * @param sql
     *            数据库SQL语句
     * @param values
     *            可选参数，相关预处理参数值
     * @return true成功，false失败
     * @throws SQLException
     *             数据库异常
     */
    public static boolean execute(Connection conn, String sql, Object... values)
            throws SQLException {
        boolean result = false;
        PreparedStatement ps = null;
        try {
            ps = conn.prepareStatement(sql);
            if (null != values && values.length > 0) {
                int item = 1;
                for (int i = 0; i < values.length; i++) {
                    if (null != values[i] && values[i].getClass().isArray()) {
                        Object[] array = (Object[]) values[i];
                        for (int j = 0; j < array.length; j++) {
                            ps.setObject(item++, array[j]);
                        }
                    } else {
                        ps.setObject(item++, values[i]);
                    }
                }
            }
            if (ps.executeUpdate() > 0) {
                result = true;
            }
        } catch (SQLException e) {
            throw e;
        } finally {
            closeAll(ps, null);
        }
        return result;
    }

    /**
     * 批量操作（增、删、改）数据库中的数据，此方法会操作同表下的数据<br/>
     * 此方法不会关闭connection
     * 
     * @param conn
     *            数据库连接
     * @param sql
     *            数据库SQL语句
     * @param values
     *            相关预处理参数值，以数组集合形式给定
     * @return true成功，false失败
     * @throws SQLException
     *             数据库异常
     */
    public static boolean execute(Connection conn, String sql,
            List<Object[]> values) throws SQLException {
        boolean result = false;
        PreparedStatement ps = null;
        try {
            conn.setAutoCommit(false);
            ps = conn.prepareStatement(sql);
            if (null != values && values.size() > 0) {
                for (int i = 0; i < values.size(); i++) {
                    Object[] objects = values.get(i);
                    for (int j = 0; j < objects.length; j++) {
                        ps.setObject(j + 1, objects[j]);
                    }
                    ps.addBatch();
                }
                ps.executeBatch();
            } else {
                DBUtil.execute(conn, sql);
            }
            conn.commit();
            result = true;
        } catch (SQLException e) {
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            throw e;
        } finally {
            try {
                conn.setAutoCommit(true);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            closeAll(ps, null);
        }
        return result;
    }

    /**
     * 批量操作（增、删、改）数据库中的数据，数据库以sql的集合形式执行，通过该方法可以批量地操作（增、删、改）数据库中不同的表中的数据<br/>
     * 此方法不会关闭connection
     * 
     * @param conn
     *            数据库连接
     * @param sqls
     *            数据库SQL语句集合
     * @return true成功，false失败
     * @throws SQLException
     *             数据库异常
     */
    public static boolean execute(Connection conn, List<String> sqls)
            throws SQLException {
        boolean result = false;
        Statement st = null;
        try {
            conn.setAutoCommit(false);
            st = conn.createStatement();
            if (null != sqls && sqls.size() > 0) {
                for (int i = 0; i < sqls.size(); i++) {
                    st.addBatch(sqls.get(i));
                }
                st.executeBatch();
                conn.commit();
                result = true;
            }
        } catch (SQLException e) {
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            throw e;
        } finally {
            try {
                conn.setAutoCommit(true);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            closeAll(st, null);
        }
        return result;
    }

    /**
     * 关闭数据库操作相关连接
     * 
     * @param st
     *            Statement连接
     * @param rs
     *            ResultSet连接
     */
    public static void closeAll(Statement st, ResultSet rs) {
        try {
            if (null != rs) {
                rs.close();
            }
            if (null != st) {
                st.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

    /**
     * 关闭数据库连接
     * 
     * @param conn
     *            数据库连接
     */
    public static void closeConnection(Connection conn) {
        try {
            if (null != conn) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
